home *** CD-ROM | disk | FTP | other *** search
/ Shareware Grab Bag / Shareware Grab Bag.iso / 005 / vol6n12.arc / REMINDER.ASM next >
Assembly Source File  |  1987-03-31  |  41KB  |  880 lines

  1. ;                      REMINDER.ASM
  2. ; Resident clock pop-up utility with hourly bell and appointment chime.
  3.  
  4. ; REMINDER [foreground color],[border color],[scan code of hot key],
  5. ;          [hourly tone frequency],[alarm tone frequency]
  6.  
  7. CODE SEGMENT                           ;*************************
  8. ASSUME CS:CODE,DS:CODE                 ;*                       *
  9. ORG 100H                               ;*  REMEMBER TO EXE2BIN  *
  10.                                        ;*                       *
  11. START:         JMP    INITIALIZE       ;*************************
  12.  
  13. ;              DATA AREA
  14. ;              ---------
  15. COPYRIGHT      DB     'Copyright 1987 Ziff-Davis Publishing Co.',1AH
  16. PROGRAMMER     DB     'Michael J. Mefford'
  17.  
  18. OLD_TIMER      DD     ?
  19. OLD_KEYBOARD   DD     ?
  20. OLD_CURSPOS    DW     ?
  21. CURSOR_TYPE    DW     ?
  22. CURSPOS        DW     325H
  23. STATUS_REG     DW     ?
  24. SCREEN_SEG     DW     0B000H
  25. TIMER_HIGH     DW     ?
  26. LAST_HOUR      DW     ?
  27. BELL_COUNT     DB     0
  28. HERTZ          DW     ?
  29.  
  30. BUSY           DB     0
  31. DISPLAY_FLAG   DB     1
  32. ALARM_FLAG     DB     1
  33. MATCH_FLAG     DB     0
  34. POPUP_FLAG     DB     0
  35. VIDEO_FLAG     DB     0
  36.  
  37. FOREGROUND     DW     07H
  38. BORDER         DW     70H
  39. HOT_KEY        DW     19
  40. HOURLY_FREQ    DW     2217
  41. ALARM_FREQ     DW     2960
  42.  
  43. DISPATCH_KEY   DB     59,60,61,62,71,72,75,77,79,80
  44. DISPATCH_TABLE DW     OFFSET ERASE     , OFFSET ALARM_ABLE
  45.                DW     OFFSET INSERT    , OFFSET DISPLAY_ABLE
  46.                DW     OFFSET HOME_KEY  , OFFSET CURS_UP
  47.                DW     OFFSET CURS_LEFT , OFFSET CURS_RIGHT
  48.                DW     OFFSET END_KEY   , OFFSET CURS_DOWN
  49.  
  50. SKIP           DB     39,42,44,45,46
  51. DIS            DB     'Dis'
  52. EN             DB     ' En'
  53. WEEKDAY        DB     'SunMonTueWedThuFriSat'
  54.  
  55.  
  56. ;************* KEYBOARD INTERCEPTOR ************;
  57.  
  58. ;-----------------------------------------------------------------;
  59. ; Let BIOS get the keystroke then see if we should pop up window. ;
  60. ;-----------------------------------------------------------------;
  61.  
  62. NEW_KEYBOARD:  STI                           ;Turn interrupts back on
  63.                PUSHF                         ;Simulate an interrupt
  64.                CALL   CS:OLD_KEYBOARD        ; by pushing flags and far call.
  65.  
  66.                PUSHF                         ;On return save all registers
  67.                PUSH   DS                     ; that will be used.
  68.                PUSH   ES
  69.                PUSH   AX
  70.                PUSH   BX
  71.                PUSH   CX
  72.                PUSH   DX
  73.                PUSH   SI
  74.                PUSH   DI
  75.                PUSH   BP
  76.  
  77.                PUSH   CS                     ;Point to our data.
  78.                POP    DS
  79.                CLD                           ;Moves in forward direction.
  80.                CMP    BUSY,0                 ;If the window is already popped
  81.                JNZ    DONE_HERE              ; exit Int 9 back to window.
  82.                CMP    VIDEO_FLAG,1           ;If graphics mode, exit.
  83.                JZ     DONE_HERE
  84.                CMP    POPUP_FLAG,1           ;If event happened, pop up.
  85.                JZ     OPEN_WINDOW
  86.                MOV    AH,1                   ;Is an ASCII character ready?
  87.                INT    16H
  88.                JZ     DONE_HERE              ;If it's just a key release, exit.
  89.                CMP    AL,0                   ;Is it extended code?
  90.                JNZ    DONE_HERE              ;If no, exit.
  91.                CMP    AH,BYTE PTR HOT_KEY    ;Else, see if our key combo.
  92.                JZ     OPEN_WINDOW            ;If yes, open window
  93. DONE_HERE:     JMP    EXIT_KEYBOARD          ; else exit.
  94.  
  95. ;------------------------------------------------------------------------;
  96. ; Save screen so we can pop up REMINDER.  Save cursor position and mode. ;
  97. ;------------------------------------------------------------------------;
  98.  
  99. OPEN_WINDOW:   OR     BUSY,1                 ;Flag that window is open.
  100.                XOR    DISPLAY_FLAG,2         ;Enable time display.
  101.                MOV    AH,0                   ;Retrieve and discard hot key
  102.                INT    16H                    ; character from keyboard buffer.
  103.                CALL   STORE_SCREEN           ;Store screen.
  104.                XOR    BH,BH
  105.                MOV    AH,3
  106.                INT    10H                    ;Retrieve
  107.                MOV    OLD_CURSPOS,DX         ; cursor mode and save.
  108.                MOV    CX,0B0CH               ;Assume monocard underscore cursor
  109.                CMP    STATUS_REG,3BAH        ;Confirm via status register.
  110.                JZ     MONO_CURSOR            ;If yes, change cursor.
  111.                MOV    CX,0607H               ;Else, assume color card cursor
  112. MONO_CURSOR:   MOV    CURSOR_TYPE,CX
  113.                MOV    AH,1                   ; and set cursor type.
  114.                INT    10H
  115.  
  116. ;-------------------------------------------;
  117. ; This is the main loop. The keyboard will  ;
  118. ; be monitored and appropriate subroutines  ;
  119. ; will service the proper key responses.    ;
  120. ;-------------------------------------------;
  121.  
  122.                ;***********;
  123.                ; MAIN LOOP ;
  124.                ;***********;
  125.  
  126. READ_KEY:      MOV    SI,OFFSET WINDOW       ;Update our window.
  127.                CALL   POP_UP
  128.                CALL   SET_CURSPOS            ;Update cursor position.
  129.                MOV    AH,0                   ;Wait for an ASCII character.
  130.                INT    16H
  131.                CMP    AL,27                  ;Is it Esc?
  132.                JZ     EXIT_WINDOW
  133.                CMP    AL,13                  ;Is it carriage return?
  134.                JNZ    CK_BS
  135.                CALL   CR
  136.                JMP    SHORT READ_KEY
  137. CK_BS:         CMP    AL,8                   ;Is it backspace?
  138.                JNZ    CK_ASCII
  139.                CALL   BS
  140.                JMP    SHORT READ_KEY
  141. CK_ASCII:      CMP    AL,0                   ;Is it an extended scan code?
  142.                JNZ    ASCII                  ;If no, it's ASCII
  143.  
  144.                CMP    AH,BYTE PTR HOT_KEY    ;Is it our key combo?
  145.                JZ     EXIT_WINDOW            ;If yes, exit window.
  146.                MOV    CX,10                  ;Check for a match with
  147.                MOV    DI,OFFSET DISPATCH_KEY ; one of the twelve extended
  148.                XCHG   AH,AL                  ; codes from our dispatch table.
  149.                REPNZ  SCASB
  150.                JNZ    READ_KEY                      ;If no match, next key.
  151.                MOV    DI,OFFSET DISPATCH_TABLE+18   ;point to end of offsets.
  152.                SHL    CX,1                          ;Double count.
  153.                SUB    DI,CX                         ;Subtract to get offset.
  154.                CALL   DS:[DI]                ;Call the subroutine.
  155.                JMP    SHORT READ_KEY         ;Then return for next key.
  156.  
  157. ASCII:         MOV    BX,CURSPOS             ;Retrieve cursor position.
  158.                CMP    BL,78                  ;Is it in last column?
  159.                JZ     READ_KEY               ;If yes, skip.
  160.                CMP    AL,32                  ;Is it space?
  161.                JZ     STORE_ASCII            ;If yes, store.
  162.                JB     READ_KEY               ;If below, skip.
  163.                CMP    BL,43                  ;Is it AM/PM column?
  164.                JNZ    STORE_ASCII            ;If no, store.
  165.                AND    AL,5FH                 ;Else, capitalize.
  166.                CMP    AL,'A'                 ;Check to see if A or P.
  167.                JZ     STORE_ASCII
  168.                CMP    AL,'P'
  169.                JNZ    READ_KEY
  170. STORE_ASCII:   CALL   STORE_CHAR
  171.                MOV    BX,1                   ;Increment cursor position.
  172.                CALL   MOVE_CURSOR
  173.  
  174.                JMP    SHORT READ_KEY
  175.  
  176.                ;***************;
  177.                ; END MAIN LOOP ;
  178.                ;***************;
  179.  
  180. ;------------------------------------;
  181. ; This is the keyboard exit routine. ;
  182. ;------------------------------------;
  183.  
  184. EXIT_WINDOW:   XOR    DISPLAY_FLAG,2         ;Restore the time display state.
  185.                MOV    SI,OFFSET SCREEN       ;Point to the stored screen
  186.                CALL   POP_UP                 ; and restore the screen.
  187.                MOV    DX,OLD_CURSPOS         ;Retrieve old cursor postion
  188.                CALL   ROW_COLUMN             ; and restore.
  189.                MOV    CX,CURSOR_TYPE         ;Retrieve old cursor type
  190.                MOV    AH,1                   ; and restore.
  191.                INT    10H
  192.                AND    POPUP_FLAG,0           ;Restore pop up flag.
  193.                AND    BUSY,0                 ;Flag done with window.
  194.  
  195. EXIT_KEYBOARD: POP    BP                     ;Restore all registers.
  196.                POP    DI
  197.                POP    SI
  198.                POP    DX
  199.                POP    CX
  200.                POP    BX
  201.                POP    AX
  202.                POP    ES
  203.                POP    DS
  204.                POPF
  205.                IRET                          ;Return from interrupt.
  206.  
  207. ;--------------------------------------;
  208. ; This subroutine retrieves and stores ;
  209. ; the upper right corner of screen.    ;
  210. ;--------------------------------------;
  211.  
  212. STORE_SCREEN:  MOV    DX,STATUS_REG          ;Retrieve the status register.
  213.                MOV    AX,SCREEN_SEG          ;Point to screen segment.
  214.                MOV    DS,AX
  215.                PUSH   CS
  216.                POP    ES
  217.                MOV    SI,70                  ;Point to start of window.
  218.                MOV    DI,OFFSET SCREEN       ;Point to storage.
  219.                MOV    BX,17                  ;17 rows to save.
  220.  
  221. READ_SCREEN:   MOV    CX,45                  ;45 characters per row.
  222. HORZ_RET1:     IN     AL,DX                  ;Get status.
  223.                TEST   AL,1                   ;Is it low?
  224.                JNZ    HORZ_RET1              ;If no, wait until it is.
  225.                CLI                           ;No more interrupts.
  226.  
  227. WAIT1:         IN     AL,DX                  ;Get status
  228.                TEST   AL,1                   ;Is it high?
  229.                JZ     WAIT1                  ;If no, wait until it is.
  230.                LODSW                         ;Retrieve a word.
  231.                STI                           ;Interrupts back on.
  232.                STOSW                         ;Store the character/attribute.
  233.                LOOP   HORZ_RET1              ;Get next byte.
  234.                ADD    SI,70                  ;Point to next row
  235.                DEC    BX
  236.                JNZ    READ_SCREEN
  237.                PUSH   CS                     ;Restore data segment.
  238.                POP    DS
  239.                RET                           ;Return.
  240.  
  241. ;-------------------------------------------------;
  242. ; This subroutine controls the position we write  ;
  243. ; to the screen and the number of rows we write.  ;
  244. ;-------------------------------------------------;
  245.  
  246. POP_UP:        MOV    DI,70                  ;Starting column 70/2 = 35
  247.                MOV    BP,17                  ;17 rows to write.
  248. NEXT_ROW1:     MOV    CX,45                  ;45 characters per row.
  249.                CALL   WRITE_SCREEN
  250.                ADD    DI,70                  ;Increment to next row.
  251.                DEC    BP
  252.                JNZ    NEXT_ROW1
  253.                RET
  254.  
  255. ;---------------------------------------------;
  256. ; This subroutine writes to the screen buffer ;
  257. ;---------------------------------------------;
  258.  
  259. WRITE_SCREEN:  MOV    DX,STATUS_REG          ;Retrieve status register
  260.                MOV    AX,SCREEN_SEG          ;Point to the screen buffer.
  261.                MOV    ES,AX
  262.  
  263. PUT_BYTE:      LODSW                         ;Get a byte.
  264.                MOV    BX,AX                  ;Store it in AX.
  265.  
  266. HORZ_RET2:     IN     AL,DX                  ;Get status.
  267.                TEST   AL,1                   ;Is it low?
  268.                JNZ    HORZ_RET2              ;If no, wait until it is.
  269.                CLI                           ;No more interrupts.
  270.  
  271. WAIT2:         IN     AL,DX                  ;Get status.
  272.                TEST   AL,1                   ;Is it high?
  273.                JZ     WAIT2                  ;If no, wait until it is.
  274.                MOV    AX,BX                  ;Retrieve the word
  275.                STOSW                         ; and store it.
  276.                STI                           ;Interrupts back on.
  277.                LOOP   PUT_BYTE               ;Write next character/attribute.
  278.                PUSH   CS
  279.                POP    ES
  280.                RET
  281.  
  282. ;-----------------------------------------------------;
  283. ; This subroutine stores what is typed in the window. ;
  284. ;-----------------------------------------------------;
  285.  
  286. STORE_CHAR:    MOV    BX,CURSPOS             ;Retrieve cursor position.
  287.                MOV    CL,AL                  ;Save character.
  288.                MOV    AX,90                  ;90 characters per row.
  289.                MUL    BH                     ;Times cursor row.
  290.                SUB    BL,35                  ;Adjust column.
  291.                SHL    BL,1                   ;Double for attributes.
  292.                XOR    BH,BH
  293.                ADD    BX,AX                  ;Add column/row for offset.
  294.                ADD    BX,OFFSET WINDOW       ;Add window offset.
  295.                MOV    [BX],CL                ;Store the character.
  296.                RET
  297.  
  298. ;-----------------------------------------------------;
  299. ; These subroutines move and set the cursor position. ;
  300. ;-----------------------------------------------------;
  301.  
  302. MOVE_CURSOR:   MOV    AX,CURSPOS             ;Retrieve current position.
  303.                ADD    AH,BH                  ;Add requested row move.
  304. NEXT_MOVE:     ADD    AL,BL                  ;Add requested column move.
  305.                MOV    CX,5                   ;Check restricted columns.
  306.                MOV    DI,OFFSET SKIP         ;Point to table.
  307.                REPNZ  SCASB
  308.                JZ     NEXT_MOVE              ;If off limits move another.
  309.                MOV    CURSPOS,AX             ;Store new position.
  310.                CALL   SET_CURSPOS            ;Move cursor.
  311.                RET
  312.  
  313. SET_CURSPOS:   MOV    DX,CURSPOS
  314. ROW_COLUMN:    XOR    BH,BH                  ;Page zero.
  315.                MOV    AH,2                   ;Move cursor via BIOS.
  316.                INT    10H
  317.                RET
  318.  
  319. ;------------------------------------------------------;
  320. ; These subroutines control the movement of the cursor ;
  321. ;------------------------------------------------------;
  322.  
  323. CURS_RIGHT:    MOV    BX,1                   ;Plus one column to move.
  324.                CMP    DL,78                  ;Already far right column?
  325.                JNZ    END_CURSOR             ;If no, move it.
  326.                RET
  327.  
  328. CURS_LEFT:     MOV    BX,0FFH                ;Minus one column to move.
  329.                CMP    DL,37                  ;Already far left column?
  330.                JNZ    END_CURSOR             ;If no, move it.
  331.                RET
  332.  
  333. CURS_UP:       MOV    BX,0FF00H              ;Minus one row to move.
  334.                CMP    DH,3                   ;Is it already top?
  335.                JNZ    END_CURSOR             ;If no, move it.
  336.                RET
  337.  
  338. CURS_DOWN:     MOV    BX,100H                ;Plus one row to move.
  339.                CMP    DH,12                  ;Is it already bottom?
  340.                JNZ    END_CURSOR             ;If no, move it.
  341.                RET
  342.  
  343. BS:            CMP    DL,37                  ;Is it already far left?
  344.                JZ     BS_RETURN              ;If yes, skip.
  345.                MOV    BX,0FFH                ;Else, minus one column to move.
  346.                CALL   MOVE_CURSOR            ;Move it.
  347.                MOV    AL,32                  ;Store space in that position.
  348.                CALL   STORE_CHAR
  349. BS_RETURN:     RET
  350.  
  351. CR:            MOV    BYTE PTR CURSPOS,37    ;Move cursor to first column.
  352.                MOV    BX,100H                ;Plus one row to move.
  353.                CMP    DH,12                  ;Already at bottom?
  354.                JNZ    END_CURSOR             ;If no, move it.
  355.                MOV    BX,0                   ;Else, zero row move.
  356.  
  357. END_CURSOR:    CALL   MOVE_CURSOR
  358.                RET
  359.  
  360. ;---------------------------------------------------;
  361.  
  362. HOME_KEY:      MOV    BYTE PTR CURSPOS,37    ;Move to first column.
  363.                JMP    SHORT END_POSITION
  364.  
  365. END_KEY:       MOV    BYTE PTR CURSPOS,78    ;Move to last column.
  366. END_POSITION:  CALL   SET_CURSPOS
  367.                RET
  368.  
  369. ;---------------------------------------------------;
  370. ; These subroutines delete a line or insert a line. ;
  371. ;---------------------------------------------------;
  372.  
  373. ERASE:         CALL   GET_COUNT              ;Prepare for moving lines.
  374.                JZ     BLANK_LINE             ;Skip if zero lines to move.
  375.                MOV    SI,DI
  376.                ADD    SI,90
  377.                REP    MOVSB                  ;Else, move the lines up
  378.                JMP    SHORT BLANK_LINE       ;Blank out bottom line.
  379.  
  380. INSERT:        CALL   GET_COUNT              ;Prepare for moving lines.
  381.                JZ     BLANK_LINE             ;Skip if zero lines to move.
  382.                MOV    SI,OFFSET WINDOW+90*12-2
  383.                MOV    DI,OFFSET WINDOW+90*13-2
  384.                STD
  385.                REP    MOVSB                  ;Else, move the lines down.
  386.                CLD
  387.                SUB    DI,88                  ;Adjust pointer.
  388.  
  389. BLANK_LINE:    MOV    AL,32                  ;Blank the line with space
  390.                MOV    AH,BYTE PTR FOREGROUND     ;and foreground color.
  391.                INC    DI
  392.                INC    DI
  393.                MOV    CX,43                      ;43 characters.
  394.                REP    STOSW
  395.                MOV    BYTE PTR DS:[DI-80],':'    ;Restore the delimiter
  396.                MOV    BYTE PTR DS:[DI-70],'M'    ; characters
  397.                MOV    BYTE PTR CURSPOS,37        ; and move the cursor.
  398.                RET
  399.  
  400. GET_COUNT:     MOV    CX,90*12               ;Assume last row.
  401.                MOV    DL,BYTE PTR CURSPOS+1  ;Retrieve cursor row.
  402.                MOV    AX,90                  ;Times 90 characters per row.
  403.                MUL    DL
  404.                MOV    DI,OFFSET WINDOW       ;Point to start of window entries
  405.                ADD    DI,AX                  ;Add offset of row and subtract
  406.                SUB    CX,AX                  ; to get characters to move.
  407.                RET
  408.  
  409. ;--------------------------------------------------------------;
  410. ; These subroutines toggle either the alarm or display status. ;
  411. ;--------------------------------------------------------------;
  412.  
  413. ALARM_ABLE:    MOV    AX,TIMER_HIGH          ;Update last hour so hourly
  414.                MOV    LAST_HOUR,AX                  ; alarm will not go off
  415.                MOV    DI,OFFSET WINDOW+(14*90)+70   ; if toggled on.
  416.                XOR    ALARM_FLAG,1                  ;Toggle alarm flag.
  417.                CMP    ALARM_FLAG,0           ;Set carry flag to indicate
  418.                JMP    SHORT SHOW_ABLE        ; status and display.
  419.  
  420. DISPLAY_ABLE:  XOR    DISPLAY_FLAG,1                ;Toggle display flag
  421.                CMP    DISPLAY_FLAG,2         ;Set carry flag.
  422.                JNZ    SHOW_TIME
  423.                MOV    AH,SCREEN+47           ;Use the attribute next door
  424.                MOV    AL,32                  ; with space to clear time
  425.                MOV    DI,OFFSET SCREEN+48    ; from screen data.
  426.                MOV    CX,21
  427.                REP    STOSW
  428. SHOW_TIME:     MOV    DI,OFFSET WINDOW+(15*90)+70
  429.                CMP    DISPLAY_FLAG,2
  430.  
  431. SHOW_ABLE:     MOV    SI,OFFSET DIS          ;If flag zero
  432.                JZ     SHOW_THIS              ; show "Disable"
  433.                MOV    SI,OFFSET EN           ; else show "Enable"
  434.  
  435. SHOW_THIS:     MOV    CX,3                   ;Move the three bytes
  436. SHOW_STORE:    MOVSB                         ; into the window.
  437.                INC    DI                     ;Bump past attribute.
  438.                LOOP   SHOW_STORE
  439.                RET
  440.  
  441. ;************* TIMER INTERCEPTOR *************;
  442.  
  443. NEW_TIMER:     STI                           ;Interrupts back on
  444.                PUSHF                         ; and save all registers
  445.                PUSH   DS                     ; that we will use.
  446.                PUSH   ES
  447.                PUSH   AX
  448.                PUSH   BX
  449.                PUSH   CX
  450.                PUSH   DX
  451.                PUSH   SI
  452.                PUSH   DI
  453.  
  454. ;-----------------------------------;
  455. ; Retrieve the video mode and time. ;
  456. ;-----------------------------------;
  457.  
  458.                CLD                           ;String moves in forward direction
  459.                PUSH   CS                     ;Point to our data.
  460.                POP    DS
  461.                MOV    AX,40H                 ;Point to BIOS data.
  462.                MOV    ES,AX
  463.                MOV    AL,ES:[49H]            ;Retrieve video mode.
  464.                MOV    CL,0                   ;Assume text mode.
  465.                CMP    AL,2                   ;Is it graphics or 40 column?
  466.                JZ     STORE_MODE             ;If no, flag as OK.
  467.                CMP    AL,3
  468.                JZ     STORE_MODE
  469.                CMP    AL,7
  470.                JZ     STORE_MODE
  471.                MOV    CL,1                   ;Else, flag as not OK.
  472. STORE_MODE:    MOV    VIDEO_FLAG,CL
  473.                MOV    CX,ES:[6CH]            ;Retrieve timer low
  474.                MOV    AX,ES:[6EH]            ; and timer high.
  475.                MOV    TIMER_HIGH,AX
  476.                PUSH   CS                     ;Restore extra segment.
  477.                POP    ES
  478.  
  479. ;---------------------------------------;
  480. ; Convert the timer to 12 hour meridian ;
  481. ; format and store in the window.       ;
  482. ;---------------------------------------;
  483.  
  484.                MOV    BL,'A'                 ;Assume AM
  485.                CMP    AX,24                  ;If midnight display AM
  486.                JE     DISPLAY_MUNDI
  487.                CMP    AX,11                  ;If before noon display AM
  488.                JBE    DISPLAY_MUNDI
  489.                MOV    BL,'P'                 ;Else, display PM.
  490. DISPLAY_MUNDI: MOV    DI,OFFSET WINDOW+86
  491.                CMP    AX,12                  ;Adjust if over 12.
  492.                JBE    DISPLAY_HOUR
  493.                SUB    AX,12
  494. DISPLAY_HOUR:  MOV    [DI],BL                ;Store either the "A" or "P".
  495.                SUB    DI,12                  ;Point to hour.
  496.                MOV    BH,1                   ;Supress leading zero.
  497.                CALL   STORE_NUMBER           ;Store hour.
  498.  
  499.                MOV    AX,CX                  ;Retrieve timer low.
  500.                XOR    DX,DX
  501.                MOV    CX,1093                ;And divide by 1093 counts
  502.                DIV    CX                     ; per minute.
  503.                MOV    BH,0                   ;Don't suppress leading zero.
  504.                MOV    CL,WINDOW+82           ;Retrieve current minute.
  505.                CALL   STORE_NUMBER           ;Store new minute.
  506.                CMP    AL,CL                  ;Check if one minute has gone by.
  507.                JZ     TIME_DONE              ;If no, skip.
  508.                MOV    MATCH_FLAG,0           ;If yes, reset match flag.
  509.  
  510. ;---------------------------------------------------;
  511. ; Display time unless disabled or in graphics mode. ;
  512. ;---------------------------------------------------;
  513.  
  514. TIME_DONE:     CMP    DISPLAY_FLAG,0         ;Skip display if display flag low
  515.                JZ     CK_MATCH
  516.                CMP    VIDEO_FLAG,1           ;Skip also if in graphics mode.
  517.                JZ     CK_MATCH
  518.  
  519. DISPLAY_TIME:  MOV    SI,OFFSET WINDOW+48    ;Point to date and time.
  520.                MOV    DI,2*59                ;Point to top left of screen.
  521.                MOV    CX,21                  ;Display the 21 characters of
  522.                CALL   WRITE_SCREEN           ; date and time.
  523.  
  524. ;----------------------------------------;
  525. ; Compare the current date and time with ;
  526. ; alarm date and time fields in window.  ;
  527. ;----------------------------------------;
  528.  
  529. CK_MATCH:      CMP    MATCH_FLAG,2
  530.                JZ     GOT_MATCH
  531.                MOV    AX,10                  ;Check the 10 possible time
  532.                MOV    BX,OFFSET WINDOW+274   ; entry fields of time with
  533. COMP_TIME:     MOV    DI,OFFSET WINDOW+74    ; the current time.
  534.                MOV    SI,BX
  535.                MOV    CX,7                   ;There are 7 bytes in time field.
  536.                REPZ   CMPSW
  537.                JZ     MATCH                  ;If match, alarm.
  538.                ADD    BX,90
  539.                DEC    AX
  540.                JNZ    COMP_TIME
  541.  
  542. ;-------------------------------------;
  543. ; If we didn't get a match with event ;
  544. ; alarm, see if the hour has changed. ;
  545. ;-------------------------------------;
  546.  
  547. HOURLY_ALARM:  CMP    ALARM_FLAG,0           ;Skip if hourly alarm is disabled
  548.                JZ     EXIT_TIMER
  549.                MOV    AX,TIMER_HIGH          ;Else, see if hour has changed
  550.                CMP    AX,LAST_HOUR
  551.                JZ     EXIT_TIMER             ;If no, exit
  552.                MOV    BX,HOURLY_FREQ         ;Else, ring hourly alarm.
  553.                CALL   BELL
  554.                JMP    SHORT EXIT_TIMER       ;And exit.
  555.  
  556. ;-----------------------------------------;
  557. ; If we have a match, ring message alarm. ;
  558. ;-----------------------------------------;
  559.  
  560. MATCH:         CMP    MATCH_FLAG,0           ;Is the message alarm done?
  561.                JNZ    EXIT_TIMER             ;If yes, exit
  562.                NEG    AX                     ;Else, subtract match count
  563.                ADD    AX,13                  ; from 13 to get cursor row.
  564.                XCHG   AH,AL
  565.                MOV    AL,37                  ;First column.
  566.                MOV    CURSPOS,AX             ;Point to matching event.
  567.                MOV    POPUP_FLAG,1           ;Flag so will pop up when able.
  568.                MOV    MATCH_FLAG,2
  569. GOT_MATCH:     MOV    BX,ALARM_FREQ          ;Ring event alarm.
  570.                CALL   BELL
  571.  
  572. EXIT_TIMER:    POP    DI                     ;Restore registers
  573.                POP    SI
  574.                POP    DX
  575.                POP    CX
  576.                POP    BX
  577.                POP    AX
  578.                POP    ES
  579.                POP    DS
  580.                POPF
  581.  
  582.                JMP    CS:OLD_TIMER           ;And service old timer interrupt.
  583.  
  584. ;--------------------------------------------------------------;
  585. ; This subroutine turns the speaker on and off for the alarms. ;
  586. ;--------------------------------------------------------------;
  587.  
  588. BELL:          CMP    BELL_COUNT,14*2        ;Toggle the speaker on and off
  589.                JNZ    START_BELL             ; 14 times.
  590.                IN     AL,61H                 ;Get timer port
  591.                AND    AL,11111100B           ; and mask off speaker bits.
  592.                OUT    61H,AL
  593.                MOV    BELL_COUNT,0           ;Reset bell counter.
  594.                MOV    AX,TIMER_HIGH          ;Update hour flag.
  595.                MOV    LAST_HOUR,AX
  596.                MOV    MATCH_FLAG,1           ;Turn off match flag for one min.
  597.                RET                           ;Return.
  598.  
  599. START_BELL:    CMP    BELL_COUNT,0           ;Is this first time through?
  600.                JNZ    TOGGLE_BELL            ;If yes, toggle the bell
  601.                MOV    AL,10110110B           ;Else, initialize the 8253.
  602.                OUT    43H,AL
  603.                MOV    DX,12H                 ;Divide 120000H by divisor.
  604.                XOR    AX,AX
  605.                DIV    BX
  606.                OUT    42H,AL                 ;Send divisor to chip.
  607.                MOV    AL,AH
  608.                OUT    42H,AL
  609.                IN     AL,61H
  610.                AND    AL,11111100B           ;Mask off speaker bits.
  611.                OUT    61H,AL
  612.  
  613.  
  614. TOGGLE_BELL:   IN     AL,61H                 ;Get port 61h
  615.                XOR    AL,00000011B           ;Toggle speaker.
  616.                OUT    61H,AL
  617.  
  618.                INC    BELL_COUNT             ;Increment bell count.
  619.                RET
  620.  
  621. ;------------------------------------------------;
  622. ; This subroutine converts the number to decimal ;
  623. ; ASCII. Leading zero suppression is checked.    ;
  624. ;------------------------------------------------;
  625.  
  626. STORE_NUMBER:  MOV    BL,10                  ;Divide by ten.
  627.                DIV    BL
  628.                ADD    AX,'00'                ;Convert to ASCII.
  629.                CMP    BH,0                   ;Suppress leading zero?
  630.                JZ     STORE_IT               ;If no, store it.
  631.                CMP    AL,'0'                 ;Else, is it leading zero?
  632.                JNZ    STORE_IT               ;If no, store it.
  633.                MOV    AL,32                  ;Else store a space character.
  634. STORE_IT:      STOSB
  635.                XCHG   AH,AL                  ;Retrieve the remainder.
  636.                INC    DI                     ;Bump past attribute.
  637.                STOSB                         ;Store it.
  638.                ADD    DI,3                   ;Point to next position.
  639.                RET
  640.  
  641. ;----------------------------------------------------------------------;
  642. ; This is the end of the resident code. Everything below is not needed ;
  643. ; after initialization so we will use the space for window storage.    ;
  644. ;----------------------------------------------------------------------;
  645.  
  646. SCREEN         LABEL  BYTE
  647. WINDOW         EQU    SCREEN+45*2*17
  648. END_RESIDENT   EQU    WINDOW+45*2*17
  649.  
  650. ;************* INITIALIZATION *************;
  651.  
  652. ;-------------------------------;
  653. ; Get the parameters and store. ;
  654. ;-------------------------------;
  655.  
  656. INITIALIZE:    CLD
  657.                CMP    BYTE PTR DS:[80H],0    ;Any parameters?
  658.                JZ     SETUP_WINDOW           ;If no, skip.
  659.                MOV    SI,82H                 ;Else, point to parameters.
  660.                MOV    DI,OFFSET FOREGROUND   ;Point to variables.
  661.                MOV    CX,5                   ;Five variables.
  662. NEXT_PARSE:    CMP    BYTE PTR [SI-1],13     ;Carriage return?
  663.                JZ     SETUP_WINDOW           ;If yes, done here.
  664.                CMP    BYTE PTR [SI],','      ;Delimiter?
  665.                JNZ    GET_IT                 ;If no, get parameter.
  666.                INC    SI                     ;Else, bump past comma.
  667.                JMP    SHORT NEXT_PARA        ;Get next parameter.
  668. GET_IT:        CALL   GET_PARA
  669.                MOV    DS:[DI],BX             ;Store parameter in variable.
  670. NEXT_PARA:     INC    DI                     ;Point to next variable.
  671.                INC    DI
  672.                LOOP   NEXT_PARSE
  673.  
  674. ;---------------------------------------------------------------;
  675. ; To keep the program to its smallest possible size, the window ;
  676. ; has been conpressed.  This routine uncompresses the data.     ;
  677. ;---------------------------------------------------------------;
  678.  
  679. SETUP_WINDOW:  MOV    AL,32                  ;Fill window with space
  680.                MOV    AH,BYTE PTR BORDER     ; and border color.
  681.                MOV    BX,OFFSET WINDOW
  682.                MOV    DI,BX
  683.                MOV    CX,45*17               ;45 columns X 17 rows.
  684.                REP    STOSW
  685.  
  686.                MOV    AL,205                       ;Double line character.
  687.                MOV    DI,OFFSET WINDOW+90+2        ;Top line.
  688.                CALL   STORE_LINE
  689.  
  690.                MOV    DI,OFFSET WINDOW+(90*13)+2   ;Middle line.
  691.                CALL   STORE_LINE
  692.  
  693.                MOV    DI,OFFSET WINDOW+(90*16)+2   ;Bottom line.
  694.                CALL   STORE_LINE
  695.  
  696.                MOV    SI,OFFSET TEXT         ;Point to text.
  697.                MOV    CX,5                   ;Placement of 5 text strings.
  698. STORE_TEXT:    LODSW                         ;Get offset.
  699.                MOV    DI,AX
  700.                ADD    DI,BX                  ;Add window offset.
  701. NEXT_TEXT:     LODSB                         ;Get character.
  702.                CMP    AL,0                   ;Is it the end?
  703.                JZ     END_TEXT
  704.                STOSB                         ;If no, store character.
  705.                INC    DI                     ;Bump past attribute.
  706.                JMP    SHORT NEXT_TEXT
  707. END_TEXT:      LOOP   STORE_TEXT
  708.  
  709.                MOV    CX,12                  ;Placement of 12 characters.
  710. STORE_BYTE:    LODSW                         ;Get offset.
  711.                MOV    DI,AX
  712.                ADD    DI,BX                  ;Add window offset.
  713.                MOVSB                         ;Store it.
  714.                LOOP   STORE_BYTE
  715.  
  716.                MOV    DH,4                   ;Placement of 4 columns of chars.
  717. STORE_MIDDLE:  LODSW                         ;Get offset.
  718.                MOV    DI,AX
  719.                ADD    DI,BX                  ;Add window offset.
  720.                LODSB                         ;Get character.
  721.                MOV    CX,10                  ;Ten rows to place.
  722. NEXT_MIDDLE:   STOSB                         ;Store it.
  723.                ADD    DI,89                  ;Next row.
  724.                LOOP   NEXT_MIDDLE
  725.                DEC    DH
  726.                JNZ    STORE_MIDDLE
  727.  
  728. ;---------------------------------------------------------;
  729. ; This routine places the foreground color in the window. ;
  730. ;---------------------------------------------------------;
  731.  
  732.                MOV    AL,BYTE PTR FOREGROUND
  733.                MOV    DI,OFFSET WINDOW+1     ;Point to top row.
  734.                MOV    CX,45                  ;45 attributes.
  735. TOP_ROW:       STOSB                         ;Store it.
  736.                INC    DI                     ;Bump past character byte.
  737.                LOOP   TOP_ROW
  738.  
  739.                MOV    BH,11                       ;11 rows.
  740.                MOV    DI,OFFSET WINDOW+(90*2)+3   ;Point to middle of window.
  741. NEXT_ROW2:     CALL   STORE_LINE                  ;Store a line.
  742.                ADD    DI,4                        ;Next row.
  743.                DEC    BH
  744.                JNZ    NEXT_ROW2
  745.  
  746.                MOV    CX,2                        ;2 rows.
  747.                MOV    DI,OFFSET WINDOW+(90*14)+5  ;Point to "F1".
  748. NEXT_FUNCT:    STOSB                              ;Store two attributes.
  749.                INC    DI
  750.                STOSB
  751.                ADD    DI,31                       ;Point to "F2".
  752.                STOSB                              ;Store two attributes.
  753.                INC    DI
  754.                STOSB
  755.                MOV    DI,OFFSET WINDOW+(90*15)+5  ;Next row.
  756.                LOOP   NEXT_FUNCT
  757.  
  758.                CALL   UPDATE_DAY             ;Place date in window.
  759.  
  760. ;----------------------------------------------------------------------;
  761. ; We need the current hour, screen buffer segment and status register. ;
  762. ;----------------------------------------------------------------------;
  763.  
  764. CARD:          MOV    AX,40H                 ;Point to ROM BIOS data area
  765.                MOV    ES,AX
  766.                MOV    AX,ES:[6EH]            ;Initialize current hour so alarm
  767.                MOV    LAST_HOUR,AX           ; won't ring upon install.
  768.                MOV    AX,ES:[63H]            ;Get base address of video card.
  769.                ADD    AX,6                   ;Convert to status register
  770.                MOV    STATUS_REG,AX          ; and store.
  771.                CMP    AX,3BAH                ;Is it mono card?
  772.                JZ     INTERRUPT              ;If yes, go to interrupt
  773.                ADD    SCREEN_SEG,800H        ; else point to color card.
  774.  
  775. ;----------------------------------------------------------------;
  776. ; Ready to install.  We will take keyboard and timer interrupts. ;
  777. ;----------------------------------------------------------------;
  778.  
  779. INTERRUPT:     MOV    AX,3509h                     ;Get keyboard interrupt.
  780.                INT    21H
  781.                MOV    WORD PTR OLD_KEYBOARD,BX     ;Save old interrupt.
  782.                MOV    WORD PTR OLD_KEYBOARD[2],ES
  783.  
  784.                MOV    DX,OFFSET NEW_KEYBOARD       ;Install new interrupt.
  785.                MOV    AX,2509h
  786.                INT    21H
  787.  
  788.                MOV    AX,351CH                     ;Get timer tick vector
  789.                INT    21H
  790.                MOV    WORD PTR OLD_TIMER,BX        ; and store offset
  791.                MOV    WORD PTR OLD_TIMER[2],ES     ; and segment.
  792.  
  793.                MOV    DX,OFFSET NEW_TIMER          ;Replace with our
  794.                MOV    AX,251CH                     ; offset and segment.
  795.                INT    21H
  796.  
  797.                MOV    DX,OFFSET END_RESIDENT+1     ;Terminate but stay resident
  798.                INT    27H
  799.  
  800. ;------------------------------------------------------------------;
  801. ; This subroutine gets the current date and puts it in the window. ;
  802. ;------------------------------------------------------------------;
  803.  
  804. UPDATE_DAY:    MOV    AH,2AH                 ;Get the date from DOS.
  805.                INT    21H
  806.                PUSH   AX                     ;Save day of week.
  807.                MOV    AL,DH                  ;Retrieve month.
  808.                XOR    AH,AH
  809.                MOV    DI,OFFSET WINDOW+48    ;Point to storage.
  810.                MOV    BH,1                   ;Suppress leading zero.
  811.                CALL   STORE_NUMBER           ;Store it.
  812.  
  813.                MOV    AL,DL                  ;Retrieve day.
  814.                XOR    AH,AH
  815.                MOV    BH,0                   ;Store leading zero.
  816.                CALL   STORE_NUMBER
  817.  
  818.                MOV    AX,CX                  ;Retrieve year.
  819.                SUB    AX,1900                ;Throw away the century half
  820.                CMP    AX,100                 ; of year; if still over one
  821.                JB     NOT_2000               ; hundred, subtract 100 for turn
  822.                SUB    AX,100
  823. NOT_2000:      CALL   STORE_NUMBER           ; of century. (planning far ahead)
  824.  
  825.                POP    AX                     ;Retrieve day of week.
  826.                MOV    CL,3                   ;Point to the appropriate
  827.                MUL    CL                     ; three character weekday
  828.                MOV    SI,OFFSET WEEKDAY      ; and move into window.
  829.                ADD    SI,AX
  830.                MOV    CX,3
  831. NEXT_WEEKDAY:  MOVSB
  832.                INC    DI                     ;Bump past attribute.
  833.                LOOP   NEXT_WEEKDAY
  834.                RET
  835.  
  836. ;----------------------------------------------;
  837. ; This subroutine stores a line of attributes. ;
  838. ;----------------------------------------------;
  839.  
  840. STORE_LINE:    MOV    CX,43                  ;43 attributes.
  841. NEXT_LINE1:    STOSB
  842.                INC    DI                     ;Bump past character.
  843.                LOOP   NEXT_LINE1
  844.                RET
  845.  
  846. ;-----------------------------------------------------------;
  847. ; This subroutine converts a command line parameter to hex. ;
  848. ;-----------------------------------------------------------;
  849.  
  850. GET_PARA:      XOR    BX,BX                  ;Start with zero.
  851. NEXT_DECIMAL:  LODSB                         ;Get a character.
  852.                CMP    AL,','                 ;Delimiter?
  853.                JBE    END_DECIMAL            ;If yes, done.
  854.                SUB    AL,30H                 ;Convert to hex.
  855.                XOR    AH,AH
  856.                MOV    BP,AX                  ;Save it in BP.
  857.                MOV    AX,10
  858.                XOR    DX,DX                  ;Shift to left by multiplying
  859.                MUL    BX                     ; last pass by ten.
  860.                MOV    BX,AX                  ;Save in BX.
  861.                ADD    BX,BP                  ;Add new number.
  862.                JMP    SHORT NEXT_DECIMAL
  863.  
  864. END_DECIMAL:   MOV    AX,BX                  ;Number in AX
  865.                RET
  866.  
  867. ;--------------------------------------------------;
  868. ; Compressed data and offsets for window structure ;
  869. ;--------------------------------------------------;
  870.  
  871. TEXT DB  10,0,'Reminder',0,184,0,'Time',0,204,0,'Appointment',0
  872.      DB  236,4,186,' F1 Delete Line   F2 Hourly Alarm  Enabled ',186,0
  873.      DB  70, 5,186,' F3 Insert Line   F4 Time Display  Enabled ',186,0
  874.      DB  52,0,'-',58,0,'-',78,0,':',88,0,'M',90,0,201,178,0,187
  875.      DB  180,0,186,12,1,186,146,4,204
  876.      DB  234,4,185,160,5,200,248,5,188,14,1,186,22,1,':',32,1,'M',102,1,186
  877.  
  878. CODE ENDS
  879. END  START
  880.